﻿using System;
using System.Collections.Generic;

namespace Core
{
    public static partial class ReferencePool
    {
        private sealed class Group
        {
            private readonly Queue<IDispose> m_queue;

            public Group(Type t)
            {
                m_queue = new Queue<IDispose>();
                Type = t;
                UsingCount = 0;
            }

            public Type Type { get; }

            public int UnusedReferenceCount
            {
                get
                {
                    lock (m_queue)
                    {
                        return m_queue.Count;
                    }
                }
            }

            public int UsingCount { get; private set; }

            public T Pop<T>() where T : IDispose
            {
                if (typeof(T) != Type)
                {
                    throw new Exception("Type is invalid.");
                }

                UsingCount++;

                lock (m_queue)
                {
                    if (m_queue.Count > 0)
                    {
                        return (T)m_queue.Dequeue();
                    }
                }

                return (T)Activator.CreateInstance(Type);
            }

            public IDispose Pop()
            {
                UsingCount++;

                lock (m_queue)
                {
                    if (m_queue.Count > 0)
                    {
                        return m_queue.Dequeue();
                    }
                }

                return (IDispose)Activator.CreateInstance(Type);
            }

            public void Push(IDispose reference)
            {
                reference.Dispose();

                lock (m_queue)
                {
                    if (EnableStrictCheck && m_queue.Contains(reference))
                    {
                        throw new Exception("The reference has been released.");
                    }

                    m_queue.Enqueue(reference);
                }

                UsingCount--;
            }

            public void RemoveAll()
            {
                lock (m_queue)
                {
                    while (m_queue.Count > 0)
                    {
                        IDispose item = m_queue.Dequeue();
                        item.Dispose();
                    }

                    m_queue.Clear();
                }
            }
        }
    }
}
